#include <linux/module.h>
#include <net/sock.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#define MY_NETLINK_TYPE 31 //max is 32, see netlink.h

struct sock *my_nl_sock = NULL;


typedef struct tagaudit_file
{
    int uid;
    char filename[256];
    int  action; // 1 write 2 read 
}__attribute__((packed)) AUDIT_DATA;

AUDIT_DATA audit_test =
{
    1001,
    "/opt/file_share/test1",
    1
};

static void hello_nl_recv_msg(struct sk_buff *skb)
{
    struct nlmsghdr *nlh;
    int pid;
    struct sk_buff *skb_out;
    int msg_size;
    char *msg=NULL;
    char *msg_zj=NULL;
    int res;
    //int i;
    printk(KERN_INFO "Entering: %s\n", __FUNCTION__);
    //msg_size = strlen(msg);
    nlh = (struct nlmsghdr *)skb->data;//Kernel Space receive message from user
    printk(KERN_INFO "Netlink receive msg: %s\n", (char *)nlmsg_data(nlh));
    msg =nlmsg_data(nlh);
    printk(KERN_INFO "msg:%s\n",msg); 
    msg_size = strlen(msg);
    printk(KERN_INFO "size of msg:%d\n",msg_size); 

    msg_size = sizeof(AUDIT_DATA);
    msg_zj = (char *)kmalloc(msg_size + 1,GFP_KERNEL);
    memset(msg_zj, 0, msg_size + 1);
    /*
    for(i = 0; i < msg_size;i++)
    {
        msg_zj[i]=msg[msg_size-i-1];
    } 
    */


    //printk(KERN_INFO "msg_zj:%s\n",msg_zj); 
    pid = nlh->nlmsg_pid;
    skb_out = nlmsg_new(msg_size, 0);
    if (!skb_out) {
        printk(KERN_INFO "alloc nlmsg failed\n");
        return;
    }
    nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, msg_size, 0);
    NETLINK_CB(skb_out).dst_group = 0;
    //strncpy(nlmsg_data(nlh), msg, msg_size);
    strncpy(nlmsg_data(nlh), msg_zj, msg_size);
    res = nlmsg_unicast(my_nl_sock, skb_out, pid);//Kernel Space send message toUser Space
    if (res < 0)
        printk(KERN_INFO "nlmsg unicast failed\n");
    kfree(msg_zj);
    return;
}

static int __init hello_init(void)
{
    struct netlink_kernel_cfg cfg = {
        .groups = 0,
        .input = hello_nl_recv_msg
    };
    printk("Entering: %s:\n", __FUNCTION__);
    my_nl_sock = netlink_kernel_create(&init_net, MY_NETLINK_TYPE, &cfg);
    if (!my_nl_sock) {
        printk(KERN_ALERT "netlink create sock failed\n");
        return -10;
    }
    return 0;
}

static void __exit hello_exit(void)
{
    printk(KERN_INFO "Exiting hello module\n");
    netlink_kernel_release(my_nl_sock);
    my_nl_sock = NULL;
}

module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
